package ru.compft.common.services;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.transaction.annotation.Transactional;
import ru.compft.common.data.AppRole;

import java.util.Collection;
import java.util.List;

/**
 * Role: VVasiliev
 * Date: 14.06.12
 * Time: 14:00
 * <p/>
 * Сервис работы с ролями
 * По умолчанию все методы только для чтения
 */
@Transactional(readOnly = true)
public interface RolesService {
    /**
     * Получение списка всех ролей системы
     * На данный метод имеют право только пользователи с определенными ролями
     * Кешируем возвращенный результат
     *
     * @return
     */
//    @PostFilter("isAuthenticated() and hasPermission(filterObject, 'READ')")
    @Cacheable(value = "roles")
    List<AppRole> getAllRoles();

    /**
     * Получение ролей от определенного индекса (from) и определенного количества (count)
     *
     * @param from
     * @param count
     * @return
     */
    @PostFilter("isAuthenticated() and hasPermission(filterObject, 'READ')")
    List<AppRole> getRoles(int from, int count);

    /**
     * Подсчитываем все роли в системе
     *
     * @return
     */
    int countAllRoles();

    /**
     * Получаем роль по ID
     * Кешируем возвращенный результат по ID
     *
     * @param roleId
     * @return
     */
    @PostFilter("isAuthenticated() and hasPermission(returnValue, 'READ')")
    @Cacheable(value = "roles", key = "#roleId")
    AppRole findRoleById(Long roleId);

    /**
     * Поиск роли по коду
     * Кешируем возвращенный результат по code
     *
     * @param code
     * @return
     */
    //    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_READ_USERS')")
    @PostFilter("isAuthenticated() and hasPermission(returnValue, 'READ')")
    @Cacheable(value = "roles", key = "#code")
    AppRole findRoleByCode(String code);

    /**
     * Создание роли
     * Очистим весь кеш для ролей.
     * В кеш помещать не будем, т.к. роль еще не создана и у нее нет ID
     *
     * @param role
     * @return
     */
    @CacheEvict(value = "roles", allEntries = true)
    AppRole addRole(AppRole role);

    /**
     * Изменение свойств роли
     * Очистим весь кеш для ролей.
     * Полученный результат поместим в кеш
     * Кеш по всем ролям снова перечитается лишь при getAllRoles()
     *
     * @param role
     * @return
     */
    @PreAuthorize("isAuthenticated() and hasPermission(#role, 'WRITE')")
    @Caching(evict = {
            @CacheEvict(value = "roles", allEntries = true)
    }, put = {
            @CachePut(value = "roles", key = "#role.id"),
            @CachePut(value = "roles", key = "#role.code")
    })
    AppRole updateRole(AppRole role);

    /**
     * Удаление роли
     * Очистим весь кеш для ролей.
     * Кеш по всем ролям снова перечитается лишь при getAllRoles()
     *
     * @param role
     * @return
     */
    @PreAuthorize("isAuthenticated() and hasPermission(#role, 'DELETE')")
    @CacheEvict(value = "roles", allEntries = true)
    Boolean deleteRole(AppRole role);

    /**
     * Специальный метод очистки кеша
     *
     * @return
     */
//    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @CacheEvict(value = "roles", allEntries = true)
    boolean clearCache();

    /**
     * Получаем список всех доступных ролей, для заданных.
     * Т.е. мы получим все дочерние роли, включая те, что переданы в параметре
     *
     * @param authorities - заданная коллекция ролей
     * @return
     */
    @Cacheable(value = "roles")
    Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<? extends GrantedAuthority> authorities);
}
